package com.example.demo.utils.treeUtil;

import lombok.Data;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 构建树形结构。
 *
 * @author Liubw
 * @since 2024-11-14
 */
@Component
public class TreeUtil implements TreeUtilService {

    public static String capitalizeFirstLetter(String str) {
        if (str == null || str.isEmpty()) {
            return "";
        }
        char firstChar = str.charAt(0);
        char capitalizedChar = Character.toUpperCase(firstChar);
        String rest = str.length() > 1 ? str.substring(1) : "";
        return "get" + capitalizedChar + rest;
    }

    @Data
    private static class InvokeClass {
        Object id = new Object();
        Object pid = new Object();
        Object label = new Object();
        Object value = new Object();
        Object type = new Object();
        List<TreeBo> children = new ArrayList<>();
    }

    private InvokeClass invokeClassByTrans(TransTreeEntity trans, Class<?> clazz, Object entity) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        InvokeClass invokeClass = new InvokeClass();
        if (!capitalizeFirstLetter(trans.getId()).isEmpty()) {
            invokeClass.setId(clazz.getDeclaredMethod(capitalizeFirstLetter(trans.getId())).invoke(entity));
        }
        if (!capitalizeFirstLetter(trans.getPid()).isEmpty()) {
            System.out.println(clazz.getDeclaredMethod(capitalizeFirstLetter(trans.getPid())));
            invokeClass.setPid(clazz.getDeclaredMethod(capitalizeFirstLetter(trans.getPid())).invoke(entity));
        }
        if (!capitalizeFirstLetter(trans.getLabel()).isEmpty()) {
            invokeClass.setLabel(clazz.getDeclaredMethod(capitalizeFirstLetter(trans.getLabel())).invoke(entity));
        }
        if (!capitalizeFirstLetter(trans.getValue()).isEmpty()) {
            invokeClass.setValue(clazz.getDeclaredMethod(capitalizeFirstLetter(trans.getValue())).invoke(entity));
        }
        if (!capitalizeFirstLetter(trans.getType()).isEmpty()) {
            invokeClass.setType(clazz.getDeclaredMethod(capitalizeFirstLetter(trans.getType())).invoke(entity));
        }
        return invokeClass;
    }

    private TreeBo setBo(InvokeClass ic) {
        TreeBo bo = new TreeBo();
        bo.setId(ic.getId().toString());
        bo.setPid(ic.getPid() == null ? "" : ic.getPid().toString());
        bo.setLabel(ic.getLabel().toString());
        bo.setValue(ic.getValue().toString());
        bo.setType(ic.getType().toString());
        bo.setChildren(ic.getChildren());
        return bo;
    }

    /**
     * list转treeList
     *
     * @param list  list数据
     * @param trans 转换模型
     * @return 树型结构化list
     */
    public List<TreeBo> list2Tree(List list, TransTreeEntity trans) {
        List<TreeBo> treeList = new ArrayList<>();
        List<TreeBo> allNodes = new ArrayList<>();
        List<TreeBo> removeNodes = new ArrayList<>();
        List<TreeBo> res = new ArrayList<>();
        try {
            for (int i = 0; i < list.size(); i++) {
                if (list.get(i).getClass() == null) {
                    throw new Exception("使用工具类TreeUtils时：未传递泛型");
                }
                allNodes.add(getChild(list, i, trans));
                for (TreeBo treeBo : allNodes) {
                    List<TreeBo> treeBos = new ArrayList<>();
                    for (TreeBo treeBo2 : allNodes) {
                        if (treeBo.getValue().equals(treeBo2.getPid())) {
                            treeBos.add(treeBo2);
                            removeNodes.add(treeBo2);
                        }
                    }
                    treeBo.setChildren(treeBos);
                    treeList.add(treeBo);
                }
            }
            TreeBo rootNode = new TreeBo();
            rootNode.setId("root");
            rootNode.setLabel(trans.getRoot());
            res.add(rootNode);// 默认根节点
            List<TreeBo> aa = treeList.stream().distinct().toList();
            List<TreeBo> bb = removeNodes.stream().distinct().toList();
            List<TreeBo> cc = aa.stream().filter(item -> !bb.contains(item)).toList();
            res.get(0).setChildren(cc);
        } catch (Exception e) {
            System.out.println("TreeUtil转换出现错误：list2Tree():" + e.toString());
            throw new RuntimeException("TreeUtil转换出现错误：list2Tree():" + e.toString());
        }
        return res;
    }

    /**
     * 二级树
     * 三参方法：要合并的父子list和转换模型。父子表字段相同时使用
     *
     * @param pList     一级节点的list，作为合并根。
     * @param childList 子节点的list
     * @param trans     父模型
     * @return 树型结构化list
     */
    @Override
    public List<TreeBo> polymerizeTree(List pList, List childList, TransTreeEntity trans) throws Exception {
        List<TreeBo> treeList = new ArrayList<>();
        List<TreeBo> res = new ArrayList<>();
        try {
            // 根节点
            TreeBo rootNode = new TreeBo();
            rootNode.setId("root");
            rootNode.setLabel(trans.getRoot());
            res.add(rootNode);
            // 一级节点
            for (int i = 0; i < pList.size(); i++) {
                treeList.add(getChild(pList, i, trans));
            }
            // 二级节点
            for (TreeBo item : treeList) {
                item = getNode(item, childList, trans);
            }
            res.get(0).setChildren(treeList);
        } catch (Exception e) {
            throw new Exception("TreeUtil转换出现错误：polymerizeTree():" + e.toString());
        }
        return res;
    }

    /**
     * 二级树
     * 四参方法：要合并的父子list和转换模型。父子表字段存在差异时，补充一个子模型
     *
     * @param pList      一级节点的list，作为合并根。
     * @param childList  子节点的list
     * @param trans      父模型
     * @param childTrans 子模型
     * @return 树型结构化list
     */
    public List<TreeBo> polymerizeTree(List pList, List childList, TransTreeEntity trans, TransTreeEntity childTrans) throws Exception {
        List<TreeBo> treeList = new ArrayList<>();
        List<TreeBo> res = new ArrayList<>();
        try {
            // 根节点
            TreeBo rootNode = new TreeBo();
            rootNode.setId("root");
            rootNode.setLabel(trans.getRoot());
            res.add(rootNode);
            TransTreeEntity ct; // 判断主子模型是否相同
            if (childTrans.getPid() == null) {
                ct = trans;
            } else {
                ct = childTrans;
            }
            // 一级节点
            for (int i = 0; i < pList.size(); i++) {
                treeList.add(getChild(pList, i, trans));
            }
            // 二级节点
            for (TreeBo item : treeList) {
                item = getNode(item, childList, ct);
            }
            res.get(0).setChildren(treeList);
        } catch (Exception e) {
            throw new Exception("TreeUtil转换出现错误：polymerizeTree():" + e.toString());
        }
        return res;
    }

    /**
     * 多级树节点
     * 四参方法：要合并的父子list和父子转换模型。 父子表字段不同时使用
     *
     * @param pList      一级节点的list，作为合并根。
     * @param childList  每层子节点的list，按层级由1-2递增顺序放入
     * @param trans      父模型
     * @param childTrans 子模型
     * @return 树型结构化list
     */

    public List<TreeBo> polymerizeTreeCycle(List pList, List<List> childList, TransTreeEntity trans, TransTreeEntity childTrans) throws Exception {
        List<TreeBo> res = new ArrayList<>();
        try {
            // 根节点
            TreeBo rootNode = new TreeBo();
            rootNode.setId("root");
            rootNode.setLabel(trans.getRoot());
            res.add(rootNode);
            TransTreeEntity ct; // 判断主子模型是否相同
            if (childTrans.getPid() == null) {
                ct = trans;
            } else {
                ct = childTrans;
            }
            List<List<TreeBo>> arr = new ArrayList<>();
            Map<String, List<TreeBo>> cache = new HashMap(); // 储存上次循环结果
            Boolean finalTime = false; // 递归中的最后一次循环
            // 递归出二级下所有
            for (int i = childList.size(); i > 0; i--) {
                if (i == 1) {
                    finalTime = true;
                }
                List list2;
                List list1;
                List<TreeBo> bo1List = new ArrayList<>();
                if (finalTime) {
                    list2 = pList;
                    list1 = childList.get(i - 1);
                } else {
                    list2 = childList.get(i - 2);
                    list1 = childList.get(i - 1);
                }
                for (int ii = 0; ii < list2.size(); ii++) {
                    List<TreeBo> bo2List = new ArrayList<>();
                    TreeBo c2;
                    if (finalTime) {
                        c2 = getChild(list2, ii, ct);
                    } else {
                        c2 = getChild(list2, ii, trans);
                    }
                    for (int xx = 0; xx < list1.size(); xx++) {
                        TreeBo c1 = getChild(list1, xx, trans);
                        if (c1.getPid().equals(c2.getValue())) {
                            // 一级和二级合并
                            c1.setChildren(cache.get(c1.getValue()));
                            bo2List.add(c1);
                        }
                    }
                    if (!bo2List.isEmpty()) {
                        // 存放当前循环中的数据，供下层循环中使用，组成树结构
                        if (cache.get(bo2List.get(0).getPid()) == null) {
                            cache.put(bo2List.get(0).getPid(), bo2List);
                        } else if (cache.get(bo2List.get(0).getPid()).size() < bo2List.size()) {
                            cache.put(bo2List.get(0).getPid(), bo2List);
                        }
                    }
                    if (finalTime) {
                        c2.setChildren(cache.get(c2.getValue()));
                        bo1List.add(c2);
                    } else {
                        if (cache.get(c2.getValue()) != null) {
                            c2.setChildren(cache.get(c2.getValue()));
                            bo1List.add(c2);
                        }
                    }
                    cache.put(c2.getPid(), bo1List.stream().filter(f -> f.getValue().equals(c2.getValue())).toList());
                }
                arr.add(bo1List);
            }

            res.get(0).setChildren(arr.get(arr.size() - 1));
        } catch (Exception e) {
            throw new Exception("TreeUtil转换出现错误：polymerizeTree():" + e.toString());
        }
        return res;
    }

    private TreeBo getChild(List pList, int i, TransTreeEntity trans) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        Class<?> clazz = pList.get(i).getClass();
        Object entity = pList.get(i);
        InvokeClass invokeClass = invokeClassByTrans(trans, clazz, entity);
        return setBo(invokeClass);
    }

    private TreeBo getNode(TreeBo item, List clist, TransTreeEntity ct) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
        List<TreeBo> deptNodeList = new ArrayList<>();
        for (int x = 0; x < clist.size(); x++) {
            Class<?> clazz = clist.get(x).getClass();
            Object entity = clist.get(x);
            InvokeClass childInvokeClass = invokeClassByTrans(ct, clazz, entity);
            if (item.getValue().equals(childInvokeClass.getPid().toString())) {
                TreeBo dto = setBo(childInvokeClass);
                deptNodeList.add(dto);
            }
            item.setChildren(deptNodeList);
        }
        return item;
    }
}

